#include "FileDuplicates.h"

#include "File.h"
#include "Directory.h"

#include <iostream>

using namespace std;

FileDuplicates::FileDuplicates(const Directory& i_directory)
  : m_directory(i_directory), m_done(false), m_failed_to_open(0), m_files(), m_duplicates()
  {
  m_files.insert(File());
  m_bytes_done = 0;
  m_bytes_todo = m_directory.GetSize();
  }

FileDuplicates::FileDuplicates(const wstring& i_dir_name)
  : m_directory(Directory(i_dir_name)), m_done(false), m_failed_to_open(0), m_files(), m_duplicates()
  {
  m_files.insert(File());
  m_bytes_done = 0;
  m_bytes_todo = m_directory.GetSize();
  }

FileDuplicates::~FileDuplicates()
  {

  }

void FileDuplicates::Search()
  {
  // push target directory in the queue
  m_scan_queue.push(Directory(m_directory));
  
  // search directories in the queue
  while (m_scan_queue.empty() == false)
    _SearchNext();
  }

void FileDuplicates::_SearchNext()
  {
  if (m_scan_queue.empty())
    return;
  
  // getting directory
  Directory dir(m_scan_queue.front());
  m_scan_queue.pop();

  wstring dir_name = dir.GetName();

  int progress = 0;
  int prev_progress = 0;
  
  // add files from directory to file set
  for (auto& file_name : dir.GetChildren(EDirectoryChildren::DC_FILES))
    {
    File f(dir_name +L'\\'+file_name);
    
    // if error occured - not to add
    if (f.IsValid() == false)
      {
      continue;
      }

    // find file in the set 
    auto p_it = m_files.insert(f);

    if (p_it.second == false)
      {
      // if same file is already in the set - add to duplicates
      wstring dup_name = (*p_it.first).GetName();
      m_duplicates[dup_name].push_back(f.GetName());
      }

    m_bytes_done += f.GetSize();

    // output progress
    progress = static_cast<int>((double)m_bytes_done/m_bytes_todo*100);
    if (progress > prev_progress)
      {
      std::wcout << '\r' << progress << '%';
      prev_progress = progress;
      }
    }  
  // push subdirectories to the queue
  for (auto& dir : dir.GetChildren(EDirectoryChildren::DC_DIRECTORIES))
    m_scan_queue.push(Directory(dir_name +L'\\' + dir));
  }
list<list<wstring>> FileDuplicates::GetDuplicates() const
  {
  return list<list<wstring>>();
  }

map<wstring, list<wstring>> FileDuplicates::GetResult() const
  {
  return m_duplicates;
  }

bool FileDuplicates::IsDone() const
  {
  return m_done;
  }

size_t FileDuplicates::GetFailedToOpen() const
  {
  return m_failed_to_open;
  }

pair<unsigned __int64, unsigned __int64> FileDuplicates::GetProgress() const
  {
  return make_pair(m_bytes_done, m_bytes_todo);
  }